package hr.ctg.web.resource;

import hr.ctg.SystemException;
import hr.ctg.domain.model.Mjesto;
import hr.ctg.domain.model.Objekt;
import hr.ctg.domain.model.Otok;
import hr.ctg.domain.model.Park;
import hr.ctg.domain.model.TipObjekta;
import hr.ctg.domain.model.Zupanija;
import hr.ctg.service.dao.MjestoDAO;
import hr.ctg.service.dao.ObjektDAO;
import hr.ctg.service.dao.OtokDAO;
import hr.ctg.service.dao.ParkDAO;
import hr.ctg.service.dao.TipObjektaDAO;
import hr.ctg.service.dao.ZupanijaDAO;

import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.web.AbstractResource;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

@Scope(ScopeType.APPLICATION)
@Name("sitemapResource")
@BypassInterceptors
public class SiteMapResource extends AbstractResource {
	private static SimpleDateFormat sdf = new SimpleDateFormat(
			"yyyy-MM-dd hh:mm:ss");
	private static final String[] lang = { "en", "hr" };

	@Override
	public void getResource(final HttpServletRequest req,
			final HttpServletResponse res) throws ServletException, IOException {

		new ContextualHttpServletRequest(req) {
			@Override
			public void process() throws IOException {
				res.setContentType("text/xml");
				res.setCharacterEncoding("UTF8");
				final MjestoDAO mjestoDAO = (MjestoDAO) Component
						.getInstance(MjestoDAO.class);
				final OtokDAO otokDAO = (OtokDAO) Component
						.getInstance(OtokDAO.class);
				final ZupanijaDAO zupanijaDAO = (ZupanijaDAO) Component
						.getInstance(ZupanijaDAO.class);
				final ObjektDAO objektDAO = (ObjektDAO) Component
						.getInstance(ObjektDAO.class);
				final TipObjektaDAO tipObjektaDAO = (TipObjektaDAO) Component
						.getInstance("tipObjektaDAO");
				final ParkDAO parkDAO = (ParkDAO) Component
						.getInstance("parkDAO");

				final PrintWriter out = res.getWriter();
				// Create XML DOM document (Memory consuming).
				Document xmldoc = null;
				final DocumentBuilderFactory factory = DocumentBuilderFactory
						.newInstance();
				DocumentBuilder builder = null;
				try {
					builder = factory.newDocumentBuilder();
				} catch (final ParserConfigurationException e1) {
					throw new SystemException(e1);
				}
				final DOMImplementation impl = builder.getDOMImplementation();
				xmldoc = impl.createDocument(
						"http://www.sitemaps.org/schemas/sitemap/0.9",
						"urlset", null);
				// Root element.
				final Element root = xmldoc.getDocumentElement();

				final Date lastmod = new Date();
				// root
				root.appendChild(createUrlElement(xmldoc,
						"http://www.crotouristguide.com", lastmod, "weekly",
						1.0));

				for (int l = 0; l < lang.length; l++) {
					// home
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/home_"
									+ lang[l], lastmod, "weekly", 0.80));
					// login
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/user/login_"
									+ lang[l], lastmod, "monthly", 0.65));
					// registration
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/user/register_"
									+ lang[l], lastmod, "monthly", 0.65));

					// guides
					root
							.appendChild(createUrlElement(xmldoc,
									"http://www.crotouristguide.com/main"
											+ lang[l] + "/travel/guides",
									lastmod, "weekly", 0.65));
					// accomodation search
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/" + lang[l]
									+ "/accomodation/search", lastmod,
							"weekly", 0.65));
					// islands
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/" + lang[l]
									+ "/islands", lastmod, "monthly", 0.65));
					// places
					@SuppressWarnings("unchecked")
					final List<String> abc = (List) Component
							.getInstance("firstMjestaLetters");
					for (final String string : abc) {
						root.appendChild(createUrlElement(xmldoc,
								"http://www.crotouristguide.com/main/"
										+ lang[l] + "/places/" + string,
								lastmod, "monthly", 0.65));
					}
					// parks
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/" + lang[l]
									+ "/parks/N", lastmod, "monthly", 0.65));
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/" + lang[l]
									+ "/parks/P", lastmod, "monthly", 0.65));
					// map
					root.appendChild(createUrlElement(xmldoc,
							"http://www.crotouristguide.com/main/" + lang[l]
									+ "/map", lastmod, "monthly", 0.65));

					// reccomendations accomodation
					List<TipObjekta> toList = tipObjektaDAO.findAll();
					for (final TipObjekta tipObjekta : toList) {
						root.appendChild(createUrlElement(xmldoc,
								"http://www.crotouristguide.com/main/"
										+ lang[l] + "/rec/accomodation/"
										+ tipObjekta.getIdTipaObjekta(),
								lastmod, "weekly", 0.65));
					}
					// zupanije
					final List<Zupanija> zupanije = zupanijaDAO.findAll();
					for (int i = 0; i < zupanije.size(); i++) {
						// root
						// .appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/"
						// + lang[l] + "/county/"
						// + zupanije.get(i).getIdZupanje(),
						// zupanije.get(i).getZadnjeAzuriranje(),
						// "monthly", 0.50));
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/county/" + zupanije.get(i).getIdZupanje()
						// + "/places", zupanije.get(i)
						// .getZadnjeAzuriranje(), "monthly", 0.50));
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/county/" + zupanije.get(i).getIdZupanje()
						// + "/islands", zupanije.get(i)
						// .getZadnjeAzuriranje(), "monthly", 0.50));

						// toList = tipObjektaDAO.findAll();
						// for (final TipObjekta tipObjekta : toList) {
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/county/"
						// + zupanije.get(i).getIdZupanje()
						// + "/objects/"
						// + tipObjekta.getIdTipaObjekta(), zupanije
						// .get(i).getZadnjeAzuriranje(), "monthly",
						// 0.50));
						// }
					}

					// otoci
					final List<Otok> otoci = otokDAO.findByObjekti();
					for (int i = 0; i < otoci.size(); i++) {
						// final Date zadnjeAzuriranje = otoci.get(i)
						// .getZadnjeAzuriranje();
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/island/" + otoci.get(i).getIdOtoka(),
						// zadnjeAzuriranje, "monthly", 0.50));
						toList = tipObjektaDAO.findAll();
						// for (final TipObjekta tipObjekta : toList) {
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/island/" + otoci.get(i).getIdOtoka()
						// + "/objects/"
						// + tipObjekta.getIdTipaObjekta(),
						// zadnjeAzuriranje, "monthly", 0.50));
						// }
					}

					// mjesta
					final List<Mjesto> mjesta = mjestoDAO.findByObjekti();
					for (int i = 0; i < mjesta.size(); i++) {
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/place/" + mjesta.get(i).getIdMjesta(),
						// mjesta.get(i).getZadnjeAzuriranje(), "monthly",
						// 0.50));
						// toList = tipObjektaDAO.findAll();
						// for (final TipObjekta tipObjekta : toList) {
						// root.appendChild(createUrlElement(xmldoc,
						// "http://www.crotouristguide.com/main/" + lang[l]
						// + "/place/" + mjesta.get(i).getIdMjesta()
						// + "objects/"
						// + tipObjekta.getIdTipaObjekta(), mjesta
						// .get(i).getZadnjeAzuriranje(), "monthly",
						// 0.50));
						// }
					}

					// objekti
					final List<Objekt> objekti = objektDAO.findAll();
					for (int i = 0; i < objekti.size(); i++) {
						root.appendChild(createUrlElement(xmldoc,
								"http://www.crotouristguide.com/main/"
										+ lang[l] + "/object/"
										+ objekti.get(i).getIdObjekta(),
								objekti.get(i).getZadnjeAzuriranje(),
								"monthly", 0.50));
					}

					// parkovi
					final List<Park> parkovi = parkDAO.findAll();
					for (int i = 0; i < parkovi.size(); i++) {
						root.appendChild(createUrlElement(xmldoc,
								"http://www.crotouristguide.com/main/"
										+ lang[l] + "/park/"
										+ parkovi.get(i).getIdParka(), objekti
										.get(i).getZadnjeAzuriranje(),
								"monthly", 0.50));
					}
				}

				// Serialisation through Tranform.
				final DOMSource domSource = new DOMSource(xmldoc);
				final StreamResult streamResult = new StreamResult(out);
				final TransformerFactory tf = TransformerFactory.newInstance();
				Transformer serializer = null;
				try {
					serializer = tf.newTransformer();
				} catch (final TransformerConfigurationException e1) {
					throw new SystemException(e1);
				}
				serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
				serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
						"users.dtd");
				serializer.setOutputProperty(OutputKeys.INDENT, "yes");
				try {
					serializer.transform(domSource, streamResult);
				} catch (final TransformerException e1) {
					throw new SystemException(e1);
				}

				out.close();
			}
		}.run();
	}

	private Element createUrlElement(final Document doc, final String loc,
			final Date lastmod, final String changefreq, final double priority) {
		final Element e = doc.createElement("url");

		final Element locEl = doc.createElement("loc");
		final Text locText = doc.createTextNode(loc);
		locEl.appendChild(locText);
		e.appendChild(locEl);

		if (lastmod != null) {
			final Element lastmodEl = doc.createElement("lastmod");
			final Text lastmodText = doc.createTextNode(sdf.format(lastmod));
			lastmodEl.appendChild(lastmodText);
			e.appendChild(lastmodEl);
		}

		final Element changefreqEl = doc.createElement("changefreq");
		final Text changefreqText = doc.createTextNode(changefreq);
		changefreqEl.appendChild(changefreqText);
		e.appendChild(changefreqEl);

		final Element priorityEl = doc.createElement("priority");
		final Text priorityText = doc.createTextNode(Double.toString(priority));
		priorityEl.appendChild(priorityText);
		e.appendChild(priorityEl);

		return e;
	}

	@Override
	public String getResourcePath() {
		return "/sitemap.xml";
	}

}
